package discovery_app

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"reflect"
	"time"

	"github.com/go-redis/redis/v8"
)

type DiscoveryService struct {
	conn             *redis.Client
	ctx              context.Context
	configs          map[string]map[string]string
	checked          map[string]int64
	redisConnections map[string]map[string]string
}

func NewDiscoveryService(conn *redis.Client) *DiscoveryService {
	return &DiscoveryService{
		conn:             conn,
		configs:          make(map[string]map[string]string, 128),
		checked:          make(map[string]int64, 128),
		redisConnections: make(map[string]map[string]string, 128),
	}
}

func (c *DiscoveryService) SetConfig(types, component string, config map[string]interface{}) {
	val, err := json.Marshal(config)
	if err != nil {
		log.Fatalln("marshal in SetConfig err: ", err)
	}
	c.conn.Set(c.ctx, fmt.Sprintf("configs:%s:%s", types, component), val, 0)
}

func (c *DiscoveryService) GetConfig(types, component string, wait int64) map[string]string {
	key := fmt.Sprintf("configs:%s:%s", types, component)
	ch, ok := c.checked[key]
	if !ok || ch < time.Now().Unix()-wait {
		c.checked[key] = time.Now().Unix()
		config := map[string]string{}
		if err := json.Unmarshal([]byte(c.conn.Get(c.ctx, key).Val()), &config); err != nil {
			config = map[string]string{}
			return nil
		}
		oldConfig := c.configs[key]
		if !reflect.DeepEqual(oldConfig, config) {
			c.configs[key] = config
		}
	}
	return c.configs[key]
}

func (c *DiscoveryService) RedisConnection(component string, wait int64) func() map[string]string {
	key := "configs:redis:" + component
	return func() map[string]string {
		oldConfig := c.configs[key]
		config := c.GetConfig("redis", component, wait)

		if !reflect.DeepEqual(config, oldConfig) {
			c.redisConnections[key] = config
		}
		return c.redisConnections[key]
	}
}
